/*
 * DbConnectionPool.cpp
 *
 *  Created on: 2018年1月3日
 *      Author: zhengboyuan
 */

#include "DbConnectionPool.h"
#include "DbUtil.h"
#include "DbPoolLock.h"
#include "soci/sqlite3/soci-sqlite3.h"
#include "SociType.h"
#include "CLog.h"


namespace db
{

DbConnectionPool::DbConnectionPool(size_t maxSize):
		m_maxSize(maxSize),
		m_pool(new soci::connection_pool(maxSize)),
        m_opened()
{
}

DbConnectionPool::~DbConnectionPool()
{
	close();

	delete m_pool;
}

bool DbConnectionPool::open(const DbSource& source)
{
	std::lock_guard< std::mutex> lock(m_mutex);

	if (!source.check())
	{
		return false;
	}

	m_source = source;
	m_backend = DbSource::toString(m_source.type);
	m_connectString = m_source.getConnectString();

	CLog::debug("DbConnectionPool::open. conn: %s\n", m_connectString.c_str());

	size_t count = 0;
	for (size_t i = 0; i < m_maxSize; ++i)
	{
		soci::session& session = m_pool->at(i);

		try
		{
            if (m_source.isSqlite())
            {
                soci::backend_factory const &backEnd = *soci::factory_sqlite3();
                session.open(backEnd, m_connectString);
            }
            else
            {
                session.open(m_backend, m_connectString);
            }
			count ++;
		}
		catch (soci::soci_error& ex)
		{
			CLog::error("soci error: %s\n", ex.what());
		}
	}

    m_opened = (count > 0);

	return (count > 0);
}

void DbConnectionPool::close()
{
	std::lock_guard< std::mutex> lock(m_mutex);

	for (size_t i = 0; i < m_maxSize; ++i)
	{
		soci::session& session = m_pool->at(i);

		try
		{
			session.close();
		}
		catch (soci::soci_error& ex)
		{
			CLog::error("soci error: %s\n", ex.what());
		}
	}

    m_opened = false;
}

bool DbConnectionPool::isOpen()
{
	return m_source.check() && m_opened;
}

size_t DbConnectionPool::maxSize() const
{
	return m_maxSize;
}

soci::connection_pool& DbConnectionPool::getPool()
{
	return *m_pool;
}

const std::string& DbConnectionPool::getBackend()
{
    return m_backend;
}

const std::string& DbConnectionPool::getConnectionStr()
{
    return m_connectString;
}

bool DbConnectionPool::reconnect()
{
	std::lock_guard< std::mutex> lock(m_mutex);

    if (m_opened)
    {
        size_t count = 0;
        for (size_t i = 0; i < m_maxSize; ++i)
        {
            soci::session& session = m_pool->at(i);

            try
            {
                if (session.get_backend() == NULL)
                {
                    session.reconnect();
                    count++;
                }
            }
            catch (soci::soci_error& ex)
            {
                CLog::error("soci error: %s\n", ex.what());
            }
        }

        return (count > 0);
    }
    else
    {
        size_t count = 0;
        for (size_t i = 0; i < m_maxSize; ++i)
        {
            soci::session& session = m_pool->at(i);

            try
            {
                session.open(m_backend, m_connectString);
                count++;
            }
            catch (soci::soci_error& ex)
            {
                CLog::error("soci error: %s\n", ex.what());
            }
        }

        m_opened = (count > 0);

        return (count > 0);
    }
}

std::mutex& DbConnectionPool::getLock()
{
    return m_mutex;
}

bool DbConnectionPool::isSqlite() const
{
    return m_source.type == DB_SQLITE;
}

const DbSource& DbConnectionPool::getSource() const
{
	return m_source;
}

bool DbConnectionPool::reopen()
{
	std::lock_guard< std::mutex> lock(m_mutex);

	size_t count = 0;
	for (size_t i = 0; i < m_maxSize; ++i)
	{
		soci::session& session = m_pool->at(i);

		try
		{
			session.close();
			session.open(m_backend, m_connectString);
			count++;
		}
		catch (soci::soci_error& ex)
		{
			CLog::error("soci error: %s\n", ex.what());
		}
	}

	return (count > 0);
}


} /* namespace db */
